package id.link.win.login.sample.login;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import sun.misc.BASE64Decoder;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.http.HttpServletRequest;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;

/**
 * Created with IntelliJ IDEA.
 *
 * @author: Foy Lian
 * Date: 8/23/2019
 * Time: 5:24 PM
 */
@Controller
public class AdPasswordSyncController {
    @RequestMapping("/openidm/managed/user")
    public void syncPassword(HttpServletRequest request,
                             @RequestParam("_action") String action, @RequestParam("_queryId") String queryId,
                             @RequestParam("uid") String username,
                             @RequestBody String json) throws Exception {

        //FIXME 请求会发送basic认证请求，应该考虑用起来增加一点安全性。参数如下：（安装idm-setup.exe时设置）
        //http header: authorization: basic YWRTeW5jOmFkU3luYw==

        //改密码的账户名
        System.out.println("username is:" + username);

/*
        post json格式:

[{ "operation" : "replace", "field" : "/password", "value" :  {   "$crypto" :    {     "value" :      {       "data" : "9OZ1vxNuTSmfE4gGeeXg0g==",       "cipher" : "AES/ECB/PKCS5Padding",       "key" :        {         "data" : "FefgemMxrHg78p8pb1UI6N9cx+fwDyAJ/qPKMBpeqh0mHT3fjox1kYW/1n8KJIjG67KsnRQVOA3jl9T+3NOnEgnIXZUpcstO4ErXNZbmc0YO7h++yXHTCyf0immhvFiw5T7CzwwR9Nzj2gtFtKPq27GuyG3VLDlqdYenw0y99VOqwmLRG10x+EdN4fgviXpgLMYUwTIz7b6d71WvF35cOtQIRfX1QGU4BgtLDfCIwYiVaa0hxxdjqdmP/iYkzdjylZieEVIetOWUEmkbYZlledV90jwfXEh3Lq381wfQvSRsxZkdWDQ8DLYtSMOMzBkvSADlk5uwlUKPQxzjsvOR2Q==",         "cipher" : "RSA/ECB/PKCS1Padding",         "key" : "test"        }      },     "type" : "x-simple-encryption"    }  }}]
*/
        System.out.println("password:" + process(json));
    }

    private static String process(String json) throws Exception {
        //FIXME 简单截取两段密文，应该使用更合适的方式
        String[] temp = json.split(":");
        List<String> dataList = new ArrayList<>();
        for (int i = 0; i < temp.length; i++) {
            if (temp[i].contains("\"data\"")) {
                dataList.add(temp[i + 1]);
            }
        }
        //截取AES加密后的密码的密文
        String encryNewPassword = dataList.get(0).replaceAll("\"", "").trim().split(",")[0];
        //截取RSA加密后的AES密码的密文
        String encryRsaKey = dataList.get(1).replaceAll("\"", "").trim().split(",")[0];
        //解密流程：1. 先用RSA私钥解密，获得AES密码； 2.使用AES密码解密得到新密码明文
        String password = decryNewPassword(encryRsaKey, encryNewPassword);
        return password;
    }


    private static String decryNewPassword(String encryRsaKey, String encryNewPassword) throws Exception {
        return decryPassword(encryNewPassword, decryAesKey((encryRsaKey)));
    }

    private static byte[] decryAesKey(String rsaEncryData) throws Exception {
        //使用RSA秘钥解密 获得AES密码原文
        KeyStore keystore = KeyStore.getInstance("PKCS12");
        //秘钥文件的密码
        char[] p12Password = "zrkj123.".toCharArray();
        //使用秘钥的别名
        String keyAlias = "test";
        //秘钥文件
        keystore.load(AdPasswordSyncController.class.getClassLoader().getResourceAsStream("test.p12"), p12Password);
        PrivateKey privateKey = (PrivateKey) keystore.getKey(keyAlias, p12Password);
        Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        return cipher.doFinal(Base64.getDecoder().decode(rsaEncryData.getBytes()));
    }

    private static String decryPassword(String encryPassword, byte[] aesKey) throws Exception {
        //使用AES密码解密获得 密码明文
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        SecretKeySpec key = new SecretKeySpec(aesKey, "AES");
        cipher.init(Cipher.DECRYPT_MODE, key);
        return new String(cipher.doFinal(new BASE64Decoder().decodeBuffer(encryPassword)));
    }

    //FIXME 手动测试代码，测试完直接删除
    public static void main(String[] args) throws Exception {
        //两组对照测试
        //RSA加密的AES解密密码
        String rsaEncryData = "FefgemMxrHg78p8pb1UI6N9cx+fwDyAJ/qPKMBpeqh0mHT3fjox1kYW/1n8KJIjG67KsnRQVOA3jl9T+3NOnEgnIXZUpcstO4ErXNZbmc0YO7h++yXHTCyf0immhvFiw5T7CzwwR9Nzj2gtFtKPq27GuyG3VLDlqdYenw0y99VOqwmLRG10x+EdN4fgviXpgLMYUwTIz7b6d71WvF35cOtQIRfX1QGU4BgtLDfCIwYiVaa0hxxdjqdmP/iYkzdjylZieEVIetOWUEmkbYZlledV90jwfXEh3Lq381wfQvSRsxZkdWDQ8DLYtSMOMzBkvSADlk5uwlUKPQxzjsvOR2Q==";
        //RSA解密，获取AES密码
        byte[] aesKey = decryAesKey(rsaEncryData);

        // 最终需要解密的密码
        String newPasswordEncryData = "9OZ1vxNuTSmfE4gGeeXg0g==";

        String newPassword = decryPassword(newPasswordEncryData, aesKey);

        System.out.println("newPassword should equal: 'zrkj123.'  ," + newPassword);

        String json = "[{ \"operation\" : \"replace\", \"field\" : \"/password\", \"value\" :  {   \"$crypto\" :    {     \"value\" :      {       \"data\" : \"9OZ1vxNuTSmfE4gGeeXg0g==\",       \"cipher\" : \"AES/ECB/PKCS5Padding\",       \"key\" :        {         \"data\" : \"FefgemMxrHg78p8pb1UI6N9cx+fwDyAJ/qPKMBpeqh0mHT3fjox1kYW/1n8KJIjG67KsnRQVOA3jl9T+3NOnEgnIXZUpcstO4ErXNZbmc0YO7h++yXHTCyf0immhvFiw5T7CzwwR9Nzj2gtFtKPq27GuyG3VLDlqdYenw0y99VOqwmLRG10x+EdN4fgviXpgLMYUwTIz7b6d71WvF35cOtQIRfX1QGU4BgtLDfCIwYiVaa0hxxdjqdmP/iYkzdjylZieEVIetOWUEmkbYZlledV90jwfXEh3Lq381wfQvSRsxZkdWDQ8DLYtSMOMzBkvSADlk5uwlUKPQxzjsvOR2Q==\",         \"cipher\" : \"RSA/ECB/PKCS1Padding\",         \"key\" : \"test\"        }      },     \"type\" : \"x-simple-encryption\"    }  }}]";

        String password = process(json);

        System.out.println("decry password from json, password should be zrkj123.  , acutal is: " + password);
    }
}
